extends Node3D
##武器的控制状态机用于控制武器的射击,动画过渡以及其他。
class_name 武器状态机
##初始状态请指定为【基础状态】,该变量只接受基础状态类型节点。。
@export var 当前状态: 基础状态

##武器资源的合集，用于调用武器资源。
@export var 背包武器资源:Array[武器资源]
##当前所持有的武器。
@export var 当前武器库:Array[String]
#之后用字典重构一下
@onready var 武器待机与腰射: Node3D = $"武器待机与腰射"
@onready var 武器瞄准与发射: Node3D = $"武器瞄准与发射"
@onready var 武器搭载节点: Node3D = $"../武器搭载节点"
@onready var 放下武器: Node3D = $"放下武器"
@onready var 玩家弹药属性: 弹药统计信息 = $"../../../玩家弹药属性"
@onready var 武器准心: Control = $"../../../UI/GUI显示与管理/玩家UI/武器准心"
@onready var 玩家属性节点: Node = $"../../../玩家属性节点"



@warning_ignore("unused_signal")
signal 武器更新信号
#@warning_ignore("unused_signal")
#signal 背包更新信号
signal 弹药更新信号



var 武器动画播放器
var 当前武器 = null  #当前武器资源的属性
var 武器堆栈 = [] #玩家可以使用的武器
var 武器指针 = 0 #用于标注当前的武器
var 武器清单={}
var 当前武器扩散:float = 0.0


#载入基础状态，基础状态也是状态机的状态模板。
func _ready() -> void:
	for child in get_children():
		if child is 基础状态:
			child.武器_状态机 = self
			#获取当前副节点下所有的子节点，因为状态机需要用到这些节点中的功能。
	await get_parent().ready
	await 初始化(当前武器库)
	#需要等父节点和子节点全部加载完成后，再进入状态机。
	当前状态.进入状态()
	GlobalSignal.武器库更新信号.connect(修改武器)
	武器搭载节点默认位置 = 武器搭载节点.position

#当渲染帧与物理帧更新时，当前状态的两种类型更新。
func _process(_delta: float) -> void:
	当前状态.渲染帧更新触发(_delta)


func _physics_process(_delta: float) -> void:
	当前状态.物理帧更新触发(_delta)
	当前武器扩散=lerp(当前武器扩散,0.0,当前武器.武器回正延迟)




func 切换状态(目标状态名:String) -> void:
	#在玩家状态机底下寻找能否有目标状态名字的节点.
	#如果没找到，则返回状态传入错误，毕竟这是一种基于节点的状态。
	var 目标状态 = get_node_or_null(目标状态名)
	if 目标状态 == null:
		printerr("武器状态机:传入状态错误，目标状态为空。")
		return
	#退出当前状态，将当前状态改为目标状态，并进入该状态。
	当前状态.退出状态()
	当前状态 = 目标状态
	当前状态.进入状态()


func 修改武器(武器名称:String,修改模式:bool):
	if 修改模式 ==true:
		if not 当前武器库.has(武器名称):
			当前武器库.push_back(武器名称)
	else :
		if 当前武器库.has(武器名称):
			当前武器库.erase(武器名称)
			武器堆栈.erase(武器名称)
	初始化(当前武器库)


func 初始化(_当前武器库:Array):
	#对玩家的武器资源进行初始化。
	for 武器 in 背包武器资源 :
		武器清单[武器.武器名称] = 武器
		#将武器资源加入清单。
	for i in 当前武器库 :
		if not 武器堆栈.has(i):
			武器堆栈.push_back(i)
		#将武器资源加入堆栈。
	当前武器 = 武器清单[武器堆栈[0]]
	print(当前武器)
	放下武器.下一把武器 =武器堆栈[武器指针]
	切换武器()
	for b in 武器堆栈 :
		var 武器场景 = 武器清单[b].武器模型绑定.instantiate()
		武器搭载节点.add_child(武器场景,true)
		武器场景.visible = false
		#生成可使用的武器场景。
	print(武器堆栈)



func _input(event: InputEvent) -> void:
	if event.is_action_pressed("上一把武器") and 当前状态==武器待机与腰射:
		if 武器指针 != 0:
			武器指针 = max(武器指针-1,0)
			放下武器.下一把武器 =武器堆栈[武器指针]
			#向状态放下武器，传输武器堆栈的指针,放下状态，以此来寻找下一把武器并连接动画术，播放动画再切换到哪起状态。
			切换武器()
		else :
			武器指针 = (武器堆栈.size()-1)
			放下武器.下一把武器 =武器堆栈[武器指针]
			切换武器()
	if event.is_action_pressed("下一把武器")and 当前状态==武器待机与腰射:
		if 武器指针 != (武器堆栈.size()-1):
			武器指针 = min(武器指针+1,武器堆栈.size()-1)
			放下武器.下一把武器 =武器堆栈[武器指针]
			切换武器()
		else :
			武器指针 =  0
			放下武器.下一把武器 =武器堆栈[武器指针]
			切换武器()




func 武器动画结束(当前动画: StringName):
	if 当前动画 == "射击" and 当前武器.全自动 == true :
		if Input.is_action_pressed("射击") and (当前状态==武器待机与腰射 or 当前状态==武器瞄准与发射):
			射击()
	if 当前动画 == "换弹" :
		切换状态("武器待机与腰射")
	if 当前动画 == "放下":
		var 武器节点 = get_node_or_null("../武器搭载节点/"+str(当前武器.武器名称))
		武器节点.visible = false
		武器动画播放器.animation_finished.disconnect(武器动画结束)
		当前武器 =  武器清单[放下武器.下一把武器]
		切换状态("拿起武器")
	if 当前动画 == "拿起":
		切换状态("武器待机与腰射")



func 切换武器():
	if 放下武器.下一把武器 != 当前武器.武器名称:
		切换状态("放下武器")
		



func 射击():
	#根据当前武器特性来更换武器发射机制。
	match 当前武器.武器特性:
		"无":
			#普通的热武器发射方式。
			普通武器特性射击()
			pass
		"蓄力":
			#蓄力后一次发射，就像弓箭。
			pass
		"充能":
			#蓄力后可以一直开火,类似哈沃克步枪。
			pass
		"单发装填":
			#只能一发一发的装填，类似于泵动霰弹枪。
			pass
	#这一部分相当繁琐。




func 普通武器特性射击():
	射击弹药计算()


func 蓄力武器特性射击():
	pass


func 充能武器特性射击():
	pass


func 单发装填武器特性射击():
	pass


func 射击弹药计算():
	if not 武器动画播放器.is_playing():
		var 库存弹药 = 玩家弹药属性.get(str(当前武器.武器类型)+"弹药")
		if 当前武器.当前武器弹容量 >= 当前武器.每次射击消耗:
			武器动画播放器.assigned_animation = "射击"
			武器动画播放器.play("射击",-1,(武器动画播放器.get_current_animation_length()/(当前武器.武器射速/玩家属性节点.射击速度加成)))
			#换弹后的第一发子弹射出动画异常大概率是这里的问题。武器动画播放器.get_current_animation_length()/
			当前武器.当前武器弹容量 -= 当前武器.每次射击消耗
			弹药更新信号.emit(当前武器.当前武器弹容量,库存弹药)
			加载投射物模组()
		else :
			if 库存弹药 !=0:
				切换状态("武器换弹")



func 加载投射物模组():
	var 武器单次扩散=当前武器.武器最小扩散 * 当前武器.武器操作性
	var 枪口检测器 = get_node("../武器搭载节点/"+ str(当前武器.武器名称) +"/枪口检测器")
	var 投射物 = 当前武器.武器射弹方案.instantiate()
	枪口检测器.add_child(投射物) 
	当前武器扩散+=武器单次扩散
	if 当前武器扩散 > 当前武器.武器最大扩散:
		当前武器扩散 =当前武器.武器最大扩散
	投射物.设置投射物(当前武器.武器射弹速度,当前武器.武器射弹本体,当前武器.武器操作性,当前武器.弹片数量,当前武器.武器伤害,当前武器扩散,当前武器.武器射程)
	



func 武器动态偏转(偏转方向:float,事件时间:float):
	武器搭载节点.rotation.z = lerp(武器搭载节点.rotation.z,-偏转方向*0.02,10*事件时间)


func 武器动态视角(鼠标事件:Vector2,事件时间:float):
	鼠标事件 = lerp(鼠标事件,Vector2.ZERO,10*事件时间)
	武器搭载节点.rotation.x = lerp(武器搭载节点.rotation.x,鼠标事件.y* 0.22,10*事件时间)
	武器搭载节点.rotation.y = lerp(武器搭载节点.rotation.y,鼠标事件.x* 0.22,10*事件时间)


var 武器搭载节点默认位置:Vector3
func 武器移动摆动(摆动幅度:float,事件时间:float):
	if 摆动幅度 > 0 and 当前状态 != 武器瞄准与发射 :
		var 摆动速度 := 0.01
		var 摆动幅度大小 := 0.01
		武器搭载节点.position.y = lerp(武器搭载节点.position.y,武器搭载节点默认位置.y +sin(Time.get_ticks_msec()*摆动速度)*摆动幅度大小,10*事件时间)
		武器搭载节点.position.x = lerp(武器搭载节点.position.x,武器搭载节点默认位置.x +sin(Time.get_ticks_msec()*摆动速度*0.5)*摆动幅度大小,10*事件时间)
	elif  当前状态 != 武器瞄准与发射:
		武器搭载节点.position.y = lerp(武器搭载节点.position.y,武器搭载节点默认位置.y,10*事件时间)
		武器搭载节点.position.x = lerp(武器搭载节点.position.x,武器搭载节点默认位置.x,10*事件时间)
